home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-09-16 | 26.0 KB | 611 lines | [TEXT/CCL2] |
- ;-*- Mode: Lisp; Package: CCL -*-
- ;;; compare utility 6/20/90
- ;;; written by Laura Bagnall Linden of TERC
-
- ;;;;;;;
- ;;; Change history
- ;;;
- ;;; 04/28/93 mwp Release
- ;;; 08/11/92 bill Michael Travers' fix to select-diff-buffer
- ;;; ------------ 2.0
- ;;; 01/22/91 bill Add compare-files-to-buffer, keep-first-version, keep-second-version
- ;;; Ported to MCL2.0 by alanr Saturday September 22,1990 5:36pm
- ;;;
- ;;;;;;
-
-
- (in-package :ccl)
-
- (locally (declare (optimize (speed 3) (safety 0)))
-
- (def-load-pointers disable-dead-keys ()
- (set-dead-keys nil)) ; allow typing <Meta>-N, etc.
-
- (defvar *show-matched-text* t
- "True if matching text should be displayed")
- (defvar *matched-lines-style* '("monaco" :plain 9)
- "Font list for lines in both files")
- (defvar *file1-lines-style* '("monaco" :bold :italic 9)
- "Font list for lines found only in file 1")
- (defvar *file2-lines-style* '("monaco" :plain :bold 9)
- "Font list for lines found only in file 2")
-
- (comtab-set-key *control-x-comtab* #\D #'(lambda(w) (eval-enqueue `(compare-buffer-to-file ,w)))
- "Compare top *fred-window* to selected file")
-
- (comtab-set-key *control-x-comtab* #\d #'(lambda(w) (eval-enqueue `(compare-buffer-to-other-buffer ,w)))
- "Compare top *fred-window* to selected other buffer")
-
- (comtab-set-key *control-x-comtab* #\c 'clear-fonts
- "Put all text in buffer in plain font")
-
- (comtab-set-key *comtab* '(:meta #\n) 'goto-next-difference
- "Move cursor to next difference in window")
-
- (comtab-set-key *comtab* '(:meta #\p) 'goto-previous-difference
- "Move cursor to previous difference in window")
-
- ; Undo works with these two commands.
- ; Also, these two will toggle if invoked with no intervening keystrokes.
- (comtab-set-key *comtab* '(:meta #\j) 'keep-first-version
- "Keep the first version of this difference")
-
- (comtab-set-key *comtab* '(:meta #\k) 'keep-second-version
- "Keep the second version of this difference")
-
- (comtab-set-key *comtab* '(:control :meta #\j) 'keep-both-versions
- "Keep both versions of this difference")
-
- (comtab-set-key *control-x-comtab* '(:control #\j) 'keep-all-first-versions
- "Keep the first versions of all unselected changes in the buffer")
-
- (comtab-set-key *control-x-comtab* '(:control #\k) 'keep-all-second-versions
- "Keep the second versions of all unselected changes in the buffer")
-
- ;;; This is the data structure used by the comparison algorithm. A buffered stream
- ;;; is a list of lines taken from a stream. The list is used in a first-in, first-out
- ;;; fashion. HEAD-PTR points to the first element of the list, and TAIL-PTR points to
- ;;; the last element of the list, allowing elements to efficiently be added to the
- ;;; end of the list. The algorithm alternately tests each element in the buffer against
- ;;; all of the elements in the other buffer. TESTED-PTR points to the last entry in the
- ;;; buffer which has been tested. COUNT is the number of entries which have been tested,
- ;;; and is always equal to (1+ (- (length head-ptr) (length tested-ptr))). Once a match
- ;;; has been found, MATCHED-PTR is used to point to the beginning of the match. The
- ;;; buffered-stream should always have at least one line in the buffer, unless the
- ;;; underlying stream is essmpty.
-
- (defstruct (bstream (:print-function print-bstream))
- (head-ptr '()) ;pointer to start of queue
- (tested-ptr '()) ;pointer to last tested entry in queue
- (tail-ptr '()) ;pointer to end of queue
- (matched-ptr '()) ;pointer to start of match
- (count 0) ;number of tested entries in queue
- stream) ;stream that the queue is buffering.
-
- (defun make-buffered-stream (&rest args)
- (declare (dynamic-extent args))
- (apply 'make-bstream args))
-
- (defun print-bstream (bstream stream depth)
- (declare (ignore depth))
- (format stream "[~S;~S;~S;~S;~S]"
- (bstream-head-ptr bstream)
- (bstream-tested-ptr bstream)
- (bstream-tail-ptr bstream)
- (bstream-matched-ptr bstream)
- (bstream-count bstream)))
-
- (defun init-buffered-stream (line stream)
- (if (eq line :eof)
- (make-buffered-stream :stream stream)
- (let ((new-pair (cons line nil)))
- (make-buffered-stream :head-ptr new-pair
- :tested-ptr new-pair
- :tail-ptr new-pair
- :count 1
- :stream stream))))
-
- (defun bstream-at-eof? (bstream)
- (empty-queue? bstream))
-
- (defun at-end? (bstream)
- (eq (bstream-head-ptr bstream) (bstream-tail-ptr bstream)))
-
- ;;; this is not to be used by functions external to the bstream abstraction.
- (defun empty-queue? (queue)
- (null (bstream-head-ptr queue)))
-
- (defun first-entry (bstream)
- (if (empty-queue? bstream)
- (error "first-entry called with an empty bstream" bstream)
- (car (bstream-head-ptr bstream))))
-
- (defun bstream-insert (line bstream &aux (new-pair (cons line nil)))
- (cond ((empty-queue? bstream) (error "this shouldn't happen"))
- (t (rplacd (bstream-tail-ptr bstream) new-pair)
- (setf (bstream-tail-ptr bstream) new-pair)
- bstream)))
-
- (defun bump-tested-ptr (bstream)
- (if (null (cdr (bstream-tested-ptr bstream)))
- (error "Can't increment tested pointer past end of buffer"))
- (setf (bstream-tested-ptr bstream) (cdr (bstream-tested-ptr bstream)))
- (incf (bstream-count bstream)))
-
- ;;; delete entry from bstream buffer, and if that's the last one, prefetch the next
- ;;; line from the stream, if there is one.
- (defun delete-and-prefetch (bstream)
- (when (eq (bstream-head-ptr bstream)
- (bstream-tail-ptr bstream))
- (buffer-next-line bstream))
- (delete-queue bstream)
- )
-
- ;;; this is not to be used by functions external to the bstream abstraction.
- (defun delete-queue (queue)
- (cond ((empty-queue? queue)
- (error "Delete called with an empty queue" queue))
- (t (when (and (eq (bstream-head-ptr queue) (bstream-tested-ptr queue))
- (not (eq (bstream-head-ptr queue) (bstream-tail-ptr queue))))
- (bump-tested-ptr queue))
- (setf (bstream-head-ptr queue) (cdr (bstream-head-ptr queue)))
- (decf (bstream-count queue))
- queue)))
-
- (defun flush-bstream (bstream output)
- (labels ((flush-queue ()
- (cond ((empty-queue? bstream)
- (stream-copy-until-eof (bstream-stream bstream)))
- (t (insert-line output(first-entry bstream))
- (delete-queue bstream)
- (flush-queue))))
- (stream-copy-until-eof (stream)
- (unless (stream-eofp stream)
- (insert-line output (read-line stream))
- (stream-copy-until-eof stream))))
- (flush-queue)))
-
-
-
- ;;; This function is the guts of the program. It uses the algorithm described in
- ;;; MPW to compare two input streams (stream1 and stream2) and outputs the result
- ;;; onto output-stream. The input streams must support the operation READ-LINE.
- ;;; The output stream must support the operations START-DIFFERENCE-ONE,
- ;;; START-DIFFERENCE-TWO, START-MATCHED-TEXT, INSERT-LINE, and PRINT-LEGEND.
-
- ;;; Description of algorithm (taken verbatim from MPW Compare facility)
-
- ;;; Both files are read and compared line for line. As soon as a mismatch is found,
- ;;; the two mismatched lines are stored in two stacks, one for each file. Lines are
- ;;; then read alternately (starting from the next input line in file2) until a match
- ;;; is found to put the files back in synchronization. If such a match is found,
- ;;; Compare writes the mismatched lines to standard output.
-
- ;;; Files are considered resynchronized when a certain number of lines in the two
- ;;; stacks exactly match. By default, the number of lines, called the grouping factor,
- ;;; is defined by the formula (truncate (+ (* 2.0 (log M 10)) 2.0)) where M is the
- ;;; number of lines saved in each stack so far. This definition requires more lines
- ;;;to be the same after larger mismatches.
-
- (defun compare (stream1 stream2 output-stream)
- (declare (optimize (speed 3) (safety 0)) (inline iter))
- (let ((bstream1 (init-buffered-stream (read-line stream1 nil :eof) stream1))
- (bstream2 (init-buffered-stream (read-line stream2 nil :eof) stream2)))
- (labels ((iter (at-eof? diff-count)
- (cond ((bstream-at-eof? bstream1)
- (cond ((bstream-at-eof? bstream2) diff-count)
- (t (unless at-eof?
- (start-difference-two output-stream))
- (insert-line output-stream (first-entry bstream2))
- (delete-and-prefetch bstream2)
- (iter t (if at-eof? diff-count (1+ diff-count))))))
- ((bstream-at-eof? bstream2)
- (unless at-eof? (start-difference-one output-stream))
- (insert-line output-stream (first-entry bstream1))
- (delete-and-prefetch bstream1)
- (iter t (if at-eof? diff-count (1+ diff-count))))
- ((string= (first-entry bstream1) (first-entry bstream2))
- (when *show-matched-text*
- (insert-line output-stream (first-entry bstream1)))
- (delete-and-prefetch bstream1)
- (delete-and-prefetch bstream2)
- (iter nil diff-count))
- (t (resynchronize bstream1 bstream2 output-stream)
- (iter nil (1+ diff-count))))))
- (iter nil 0))))
-
- (defun resynchronize (bstream1 bstream2 output)
- (cond ((match bstream1 bstream2)
- ;;(format t "bstream1: ~S,~%bstream2: ~S~%" bstream1 bstream2)
- (start-difference-one output)
- (output-differences bstream1 output)
- (start-difference-two output)
- (output-differences bstream2 output)
- ;;(format t "bstream1: ~S,~%bstream2: ~S~%" bstream1 bstream2)
- (start-matched-text output)
- (output-matched-text bstream1 bstream2 output)
- ;;(format t "bstream1: ~S,~%bstream2: ~S~%" bstream1 bstream2)
- )
- (t (start-difference-one output)
- (flush-bstream bstream1 output)
- (start-difference-two output)
- (flush-bstream bstream2 output))
- ))
-
- (defun output-differences (bstream output)
- (declare (optimize (speed 3) (safety 0)) (inline loop))
- (labels ((loop (l)
- (cond ((eq l (bstream-matched-ptr bstream)) bstream)
- (t (insert-line output(first-entry bstream))
- (delete-queue bstream)
- (loop (cdr l))))))
- (loop (bstream-head-ptr bstream))))
-
- (defun output-matched-text (bstream1 bstream2 output)
- (declare (optimize (speed 3) (safety 0)) (inline loop))
- (labels ((loop ()
- (cond ((at-end? bstream1) (buffer-next-line bstream1))
- ((at-end? bstream2) (buffer-next-line bstream2))
- ((string/= (first-entry bstream1) (first-entry bstream2))
- (error "This shouldn't happen"))
- (t (when *show-matched-text*
- (insert-line output (first-entry bstream1)))
- (delete-queue bstream1)
- (delete-queue bstream2)
- (loop)))))
- (loop)))
-
- ;;; Given two buffered streams, bstream1 and bstream2, tries to match the first
- ;;; untested entry in bstream1 against all the entries in bstream2. If it succeeds,
- ;;; then it outputs the entries already tested as differences, otherwise, it repeats
- ;;; the process with the next line in bstream2.
- (defun match (bstream1 bstream2)
- (declare (optimize (speed 3) (safety 0)) (inline loop))
- (let ((first-untested-entry (next-entry (bstream-tested-ptr bstream1) bstream1)))
- (labels ((loop (entry-to-compare count)
- (cond ((null first-untested-entry) nil)
- ((zerop count)
- (bump-tested-ptr bstream1)
- (match bstream2 bstream1))
- ((match-entry first-untested-entry bstream1
- entry-to-compare bstream2
- (group-factor (bstream-count bstream1)))
- (setf (bstream-matched-ptr bstream1) first-untested-entry)
- (setf (bstream-matched-ptr bstream2) entry-to-compare)
- t)
- (t (loop (next-entry entry-to-compare bstream2) (1- count))))))
- (loop (bstream-head-ptr bstream2) (bstream-count bstream2))
- )))
-
- (defun group-factor (m)
- (check-type m (integer 1 *) "a positive integer")
- (truncate (+ (* 2.0 (log M 10)) 2.0)))
-
- (defun match-entry (ptr1 bstream1 ptr2 bstream2 depth)
- (cond ((zerop depth) t)
- ((or (null ptr1) (null ptr2)) nil)
- ((string/= (car ptr1) (car ptr2)) nil)
- (t (match-entry (next-entry ptr1 bstream1)
- bstream1
- (next-entry ptr2 bstream2)
- bstream2
- (1- depth)))
- ))
-
- (defun next-entry (ptr bstream)
- (if (null (cdr ptr))
- (buffer-next-line bstream)
- (cdr ptr)))
-
- (defun buffer-next-line (bstream)
- (let ((line (read-line (bstream-stream bstream) nil :eof)))
- (unless (eq line :eof)
- (bstream-insert line bstream)
- (bstream-tail-ptr bstream))))
-
- (defclass difference-output-stream (stream)
- ((stream :accessor stream :initarg :stream :initform *standard-output*)))
-
- (defmethod start-difference-one ((s difference-output-stream))
- (format (stream s) "*** Start of difference in first file ***~%"))
-
- (defmethod start-difference-two ((s difference-output-stream))
- (format (stream s) "*** Start of difference in second file ***~%"))
-
- (defmethod start-matched-text ((s difference-output-stream))
- (format (stream s) "*** End of differences ***~%"))
-
- (defmethod insert-line ((s difference-output-stream) line)
- (stream-write-string (stream s) line 0 (length line))
- (terpri (stream s)))
-
- (defmethod print-legend ((s difference-output-stream) name1 name2)
- (format (stream s) "Comparison of ~A with ~A~%" name1 name2))
-
- (defmethod stream-close ((s difference-output-stream))
- (close (stream s)))
-
- (defun compare-files (file1 file2 &optional filename)
- (with-open-file (s1 file1)
- (with-open-file (s2 file2)
- (with-open-stream
- (output (make-instance 'difference-output-stream
- :stream (if filename
- (open filename :direction :output
- :if-exists :append
- :if-does-not-exist :create)
- *standard-output*)))
- (print-legend output file1 file2)
- (format t "~D differences found" (compare s1 s2 output))))))
-
- ;;; The next bit of code will define a subclass FRED-DIFF-WINDOW which inherits both
- ;;; from DIFFERENCE-OUTPUT-STREAM and FRED-WINDOW.
-
- (defclass fred-diff-window (fred-window difference-output-stream) ()
- (:default-initargs :window-title "Source Compare"))
-
- (defun difference-marks (w)
- (buffer-getprop (fred-buffer w) 'difference-marks nil))
-
- (defun (setf difference-marks) (value w)
- (buffer-putprop (fred-buffer w) 'difference-marks value))
-
- (defmethod start-difference-one ((w fred-diff-window))
- (setf (difference-marks w)
- (nconc (difference-marks w)
- (list (list (make-mark (fred-buffer w)
- (buffer-position (fred-buffer w)) t)
- nil
- nil))))
- (buffer-set-font-spec (fred-buffer w) *file1-lines-style*)
- (set-mark (fred-display-start-mark w) (fred-buffer w))
- (window-update-event-handler w))
-
- (defmethod start-difference-two ((w fred-diff-window))
- (let* ((last (last (difference-marks w)))
- (buf (fred-buffer w))
- (mark (make-mark buf (buffer-position buf) t)))
- (if (and last (null (second (car last))))
- (setf (second (car last)) mark)
- (let ((new (list (list mark mark nil))))
- (if last
- (setf (cdr last) new)
- (setf (difference-marks w) new))))
- (buffer-set-font-spec buf *file2-lines-style*)))
-
- (defmethod start-matched-text ((w fred-diff-window))
- (let ((last (car (last (difference-marks w)))))
- (when (and last (null (third last)))
- (let* ((buf (fred-buffer w))
- (mark (make-mark buf (buffer-position buf) t)))
- (unless (second last)
- (setf (second last) mark))
- (setf (third last) mark))))
- (buffer-set-font-spec (fred-buffer w) *matched-lines-style*))
-
- (defmethod insert-line ((w fred-diff-window) text)
- (ed-insert-with-style w text nil)
- (terpri w)
- ; (window-update-event-handler w)
- )
-
- (defmethod print-legend ((w fred-diff-window) name1 name2)
- (buffer-set-font-spec (fred-buffer w) *file1-lines-style*)
- (ed-insert-with-style w
- (format nil "; THIS IS IN «~a», but not «~a».~%" name1 name2)
- nil)
- (buffer-set-font-spec (fred-buffer w) *file2-lines-style*)
- (ed-insert-with-style w
- (format nil "; THIS IS IN «~a», but not «~a».~%"
- name2 name1)
- nil)
- (buffer-set-font-spec (fred-buffer w) *matched-lines-style*)
- (ed-insert-with-style w
- (format nil "; «»«»«»«»«»«»«»«»«»«»«»«»«»«»~%~%")
- nil)
- (window-update-event-handler w))
-
- (defmacro with-mark ((name buffer position) &body body)
- `(let ((,name (make-mark ,buffer ,position)))
- ,@body))
-
- (defmacro with-fred-stream ((stream-var fred-window) &body body)
- `(let ((,stream-var (window-selection-stream ,fred-window 0 t)))
- ,@body))
-
- (defun compare-buffer-to-file (f1)
- (let ((f2 (choose-file-dialog :button-string "File 2")))
- (when f2
- (with-fred-stream (stream1 f1)
- (with-open-file (stream2 f2)
- (let ((output (make-instance 'fred-diff-window)))
- (print-legend output (window-filename f1) f2)
- (set-mini-buffer output "Getting diffs …")
- (set-mini-buffer output (format nil "~D differences found"
- (compare stream1 stream2 output)))
- (start-matched-text output) ; ensure last difference-mark is complete
- (set-mark (fred-buffer output) 0)
- (window-update-event-handler output)
- (window-set-not-modified output)
- ))))))
-
- (defun compare-buffer-to-other-buffer (f1)
- (let ((f2 (select-diff-buffer f1)))
- (when f2
- (with-fred-stream (stream1 f1)
- (with-fred-stream (stream2 f2)
- (let ((output (make-instance 'fred-diff-window)))
- (print-legend output (window-filename f1) (window-filename f2))
- (set-mini-buffer output "Getting diffs …")
- (set-mini-buffer output (format nil "~D differences found"
- (compare stream1 stream2 output)))
- (start-matched-text output) ; ensure last difference-mark is complete
- (set-mark (fred-buffer output) 0)
- (window-update-event-handler output)
- (window-set-not-modified output)))))))
-
- (defun compare-files-to-buffer (from-file to-file &optional (output-file to-file))
- (with-open-file (stream1 from-file)
- (with-open-file (stream2 to-file)
- (let ((*show-matched-text* t)
- (output (make-instance 'fred-diff-window :window-show nil)))
- (set-window-filename output output-file)
- (view-restore-position output)
- (window-show output)
- ; (print-legend output from-file to-file)
- (set-mini-buffer output "Getting diffs …")
- (let ((diffs (compare stream1 stream2 output)))
- (when (eql 0 diffs)
- (window-set-not-modified output)
- (window-close output)
- (return-from compare-files-to-buffer 0))
- (start-matched-text output) ; ensure last difference-mark is complete
- (set-mini-buffer output (format nil "~D differences found" diffs))
- (set-mark (fred-buffer output) 0)
- (goto-next-difference output)
- (window-show-cursor output)
- (values diffs output))))))
-
- (defun select-diff-buffer (current)
- (car (select-item-from-list
- (delete-if #'(lambda (w) (typep w 'listener))
- (remove current
- (windows :class 'fred-window
- :include-invisibles t)))
- :table-print-function #'(lambda (w stream)
- (princ (or (window-filename w)
- (window-title w))
- stream))
- :window-title (format nil "Compare \"~A\" to:"
- (or (window-filename current)
- (window-title current))))))
-
- (defmethod clear-fonts ((w fred-window))
- (buffer-set-font-spec (fred-buffer w) '(:plain)
- 0 (buffer-size (fred-buffer w))))
-
- (defun find-next-difference (w &optional (pos (fred-buffer w)))
- (unless (integerp pos) (setq pos (buffer-position pos)))
- (let (mark)
- (dolist (marks (difference-marks w))
- (when (and (setq mark (car marks))
- (< pos (buffer-position mark)))
- (return mark)))))
-
- (defun find-previous-difference (w &optional (pos (fred-buffer w)))
- (unless (integerp pos) (setq pos (buffer-position pos)))
- (let (mark last-mark)
- (dolist (marks (difference-marks w))
- (when (and (setq mark (car marks))
- (<= pos (buffer-position mark)))
- (return last-mark))
- (setq last-mark mark))))
-
- (defun goto-next-difference (w &optional quiet-p)
- (let ((next-mark (find-next-difference w)))
- (if next-mark
- (set-mark (fred-buffer w) next-mark)
- (progn (unless quiet-p (ed-beep)) nil))))
-
- (defun goto-previous-difference (w &optional quiet-p)
- (let ((next-mark (find-previous-difference w)))
- (if next-mark
- (set-mark (fred-buffer w) next-mark)
- (progn (unless quiet-p (ed-beep)) nil))))
-
- (defun difference-range (w &optional (pos (fred-buffer w)))
- (unless (integerp pos) (setq pos (buffer-position pos)))
- (dolist (marks (difference-marks w))
- (when (and (first marks)
- (>= pos (buffer-position (first marks)))
- (<= pos (buffer-position (third marks))))
- (return (values (buffer-position (first marks))
- (buffer-position (second marks))
- (buffer-position (third marks))
- marks)))))
-
- (defun keep-first-version (w)
- (keep-version w #'(lambda (buf start middle end)
- (declare (ignore end))
- (buffer-substring buf start middle))))
-
- (defun keep-second-version (w)
- (keep-version w #'(lambda (buf start middle end)
- (declare (ignore start))
- (buffer-substring buf middle end))))
-
- (defun keep-both-versions (w)
- (keep-version w #'(lambda (buf start middle end)
- (declare (ignore middle))
- (buffer-substring buf start end))))
-
- (defun keep-all-first-versions (w)
- (set-mark (fred-buffer w) 0)
- (setq *last-command* nil)
- (when (difference-range w) (keep-first-version w))
- (loop
- (unless (goto-next-difference w t) (return))
- (setq *last-command* nil)
- (keep-first-version w)))
-
- (defun keep-all-second-versions (w)
- (set-mark (fred-buffer w) 0)
- (setq *last-command* nil)
- (when (difference-range w) (keep-second-version w))
- (loop
- (unless (goto-next-difference w t) (return))
- (setq *last-command* nil)
- (keep-second-version w)))
-
- (defun keep-version (w keep-string-function)
- (let ((show-cursor-p nil))
- (if (and (eq 'keep-version *last-command*)
- (window-can-do-operation w 'undo))
- (undo w))
- (setq show-cursor-p t)
- (multiple-value-bind (start middle end marks) (difference-range w)
- (if (not start)
- (ed-beep)
- (let* ((buf (fred-buffer w))
- (undo-string (buffer-substring buf start end))
- (undo-style (buffer-get-style buf start end))
- (redo-string (funcall keep-string-function buf start middle end)))
- (labels ((undo ()
- (buffer-delete buf start (+ start (length redo-string)))
- (buffer-insert-with-style buf undo-string undo-style start)
- (setf (first marks) (make-mark buf start t)
- (second marks) (make-mark buf middle)
- (third marks) (make-mark buf end))
- (set-mark buf start)
- (when show-cursor-p (window-show-cursor w))
- (set-fred-last-command w nil)
- (setup-undo w #'redo "Redo"))
- (redo ()
- (buffer-delete buf start end)
- (buffer-insert buf redo-string start)
- (setf (first marks) nil)
- (set-mark buf start)
- (when show-cursor-p (window-show-cursor w))
- (set-fred-last-command w 'keep-version)
- (setup-undo w #'undo "Undo")))
- (redo)))))))
-
- );
-
-
-
-
- ;;; ***** List of things to do. *****
-
- ;;; What I would like to do is not to do any display until the first difference is found,
- ;;; and if no differences exist, than not to do any display. However, this would mean
- ;;; that the files would have to be reread from the beginning if differences are found.
- ;;; Thus, I am choosing the alternative which is to go ahead and create the output
- ;;; window, and if the file are the same, then close the output-stream and throw control
- ;;; back to the calling function which will display some appropriate message stating that
- ;;; no differences were found.
- ;;; [Note: (ask random-window (window-close)) makes windows go away
-
-
-
- (provide :compare)